"""

simulinkParser

Implementatin of a simple Simulink parser.
Based on jsonParser.py by Paul McGuire


"""

SIMULINK_BNF = """
object
    { members }
    {}
members
    string : value
    members , string : value
array
    [ elements ]
    []
matrix
    [elements ; elements]
    []
elements
    value
    elements , value
value
    string
    float
    integer
    object
    list
    array
    on
    off
    null
"""

testdata = """
System {
    Name		    "feedbackloop"
    Location		    [480, 85, 1016, 386]
    Open		    on
    ModelBrowserVisibility  off
    ModelBrowserWidth	    200
    ScreenColor		    "white"
    PaperOrientation	    "landscape"
    PaperPositionMode	    "auto"
    PaperType		    "A4"
    PaperUnits		    "centimeters"
    TiledPaperMargins	    [0.500000, 0.500000, 0.500000, 0.500000]
    TiledPageScale	    1
    ShowPageBoundaries	    off
    ZoomFactor		    "100"
    ReportName		    "simulink-default.rpt"
    Simulink.ConfigSet {
    $PropName		    "ActiveConfigurationSet"
    $ObjectID		    1
  }
  Simulink.ConfigSet {
    $PropName		    "ActiveConfigurationSet"
    $ObjectID		    1
  }
    Block {
      BlockType		      Inport
      Name		      "In1"
      Position		      [100, 73, 130, 87]
      IconDisplay	      "Port number"
    }
    Block {
      BlockType		      Integrator
      Name		      "Integrator"
      Ports		      [1, 1]
      Position		      [220, 65, 250, 95]
      IgnoreLimit	      off
    }
    Block {
      BlockType		      Sum
      Name		      "Sum"
      Ports		      [2, 1]
      Position		      [160, 70, 180, 90]
      ShowName		      off
      IconShape		      "round"
      Inputs		      "|++"
      CollapseMode	      "All dimensions"
      InputSameDT	      off
      OutDataTypeMode	      "Inherit via internal rule"
      SaturateOnIntegerOverflow	off
    }
    Block {
      BlockType		      Outport
      Name		      "Out1"
      Position		      [345, 73, 375, 87]
      IconDisplay	      "Port number"
      BusOutputAsStruct	      off
    }
    Line {
      SrcBlock		      "Integrator"
      SrcPort		      1
      Points		      [35, 0]
      Branch {
	Points			[0, -45; 40, 0]
	DstBlock		"Out1"
	DstPort			1
      }
      Branch {
	Points			[0, 70; -25, 0]
	Branch {
	  Points		  [-95, 0]
	  DstBlock		  "Sum"
	  DstPort		  2
	}
	Branch {
	  Points		  [0, 40; -135, 0]
	}
      }
    }
    Line {
      SrcBlock		      "In1"
      SrcPort		      1
      DstBlock		      "Sum"
      DstPort		      1
    }
    Line {
      SrcBlock		      "Sum"
      SrcPort		      1
      DstBlock		      "Integrator"
      DstPort		      1
    }
  }
 }
"""

testdata2 = """
System {
        Name		    "feedbackloop"
        Location		    [480, 85, 1016, 386]
        Open		    on
        TiledPaperMargins	    [0.500000, 0.500000, 0.500000, 0.500000]
        Block {
            BlockType    Fcn
            Name	     "Fcn"
            Position     [120, 50, 180, 80]
                        Expr	     "sin(u(1)*exp(2.3*(-u(2))))+sin(u(1)*exp(2.3*(-u"
 "(2))))+sin(u(1))"
        }
        Block {
          BlockType		      Outport
          Name		      "Out1"
          Position		      [345, 73, 375, 87]
          IconDisplay	      "Port number"
          BusOutputAsStruct	      off
        }
        Line {
          SrcBlock		      "Integrator"
          SrcPort		      1
          Points		      [35, 0]
          Branch {
    	      Points			[0, -45; 40, 0]
    	      DstBlock		"Out1"
    	      DstPort			1
          }
        }
    }
    """
    
from pyparsing import Keyword, dblQuotedString, removeQuotes, Combine, Optional,\
                      Forward, alphas, nums, OneOrMore, delimitedList, Word,\
                      LineStart, Group, Suppress, LineEnd



# parse actions
def convertNumbers(s,l,toks):
    """Convert tokens to int or float"""
    # Taken from jsonParser.py
    n = toks[0]
    try:
        return int(n)
    except ValueError, ve:
        return float(n)

def joinStrings(s,l,toks):
    """Join string split over multiple lines"""
    return ["".join(toks)]

mdlparser = None
def createMdlParser():
    global mdlparser
    if not mdlparser:
        # Define grammar
        dblString = dblQuotedString.setParseAction( removeQuotes )
        mdlNumber = Combine( Optional('-') + ( '0' | Word('123456789',nums) ) +
                            Optional( '.' + Word(nums) ) +
                            Optional( Word('eE',exact=1) + Word(nums+'+-',nums) ) )
        mdlObject = Forward()
        mdlName = Word('$'+'.'+alphas+nums)
        mdlValue = Forward()
        # Strings can be split over multiple lines
        mdlString = (dblString + Optional(OneOrMore(Suppress(LineEnd())+ LineStart() + dblString)))
        mdlElements = delimitedList( mdlValue )
        mdlArray = Group(Suppress('[') + Optional(mdlElements) + Suppress(']') )
        mdlMatrix =Group(Suppress('[') + (delimitedList(Group(mdlElements),';')) \
                      + Suppress(']') )
        mdlValue << ( mdlNumber | mdlName| mdlString  | mdlArray | mdlMatrix )
        memberDef = Group( mdlName  + mdlValue ) | Group(mdlObject)
        mdlMembers = OneOrMore( memberDef)
        mdlObject << ( mdlName+Suppress('{') + Optional(mdlMembers) + Suppress('}') )
        mdlNumber.setParseAction( convertNumbers )
        mdlString.setParseAction(joinStrings)
        mdlparser = mdlObject
    return mdlparser

        
def parseMdlFile(filename):
    """Parse a mdl file"""
    data = open(filename).read()
    return mdlparser.parseString(data)
    
def extractBlocks(system):
    # Extract all blocks
    # extract all blocks
    blocklist = [i for i in system[0] if i[0]=="Block"]
    blocks = {}
    for block in blocklist:
        d = {}
        for attr in block[1:]:
            if len(attr) == 2:
               d[attr[0]]=attr[1][:]

        blocks[d['Name']] = d
    return blocks

def extractAnnotations(data):
    # Extract all blocks
    # extract all blocks
    annotationlist = [i for i in system[0] if i[0]=="Annotation"]
    annotations = []
    for ann in annotationlist:
        d = {}
        for attr in ann[1:]:
            if len(attr) == 2:
               d[attr[0]]=attr[1][:]

        annotations.append(d)
    return annotations

TEST_FILE = 'd:/pycode/textools/mdlconv/experiments/test.tex'

templatea = """
\documentclass{article}
\usepackage{tikz}
\\begin{document}
\\begin{tikzpicture}[scale=0.02, yscale=-1]
"""

templateb = """
\end{tikzpicture}
\end{document}
"""


def outputBlocks(blocks):
    s = templatea
    for name,block in blocks.items():
        pos = block['Position']
        s+= "\draw (%s,%s) rectangle (%s,%s);%%%s\n" % (pos[0],pos[1],pos[2],pos[3],name)
    s += templateb
    f = open(TEST_FILE,'w')
    f.write(s)
    f.close()
    print s
    
        
    

sparser = createMdlParser()
results = sparser.parseString(testdata2)
print results.asList()
results = parseMdlFile('subsystem2.mdl')
print results.asList()
#data = results
#system = [i for i in data if i[0]=="System"]
#blocks = extractBlocks(system)
#outputBlocks(blocks)
# extract lines
#linelist = [i for i in data if i[0]=="Line"]
#lines = []
#for line in linelist:
#    d = dict(line[1:])
#    lines.append(d)

